package lamps;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Random;
import java.util.concurrent.CountDownLatch;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

import bean.ClientBean;
import bean.ServerBean;
import util.Util;

public class Lamps extends JFrame implements ActionListener{
	//序列号
	private static final long serialVersionUID = 1L;
	//虚拟路灯面板
	private static JPanel contentPane;
	//客户端socket
	private static Socket clientSocket;
	//对象输出流
	private static ObjectOutputStream oos;
	//对象输入流
	private static ObjectInputStream ois;
	//路灯id
	private static String lightId;
	//感知温度信息框
	private static JTextPane textpane_Tem;
	//感知湿度信息框
	private static JTextPane textpane_Hum;
	//感知环境照度信息框
	private static JTextPane textpane_Light;
	//路灯连接ip信息框
	private static JTextPane textpane_Addr;
	//显示路灯开关状态的按钮
	private static JButton btnNewButton_state;
	//为true时，路灯将停止向服务器发送数据
	private static boolean sendStop = false;
	//随机数生成器
	private static Random random = new Random();
	//路灯状态，true为开，false为关
	private static boolean state;
	//工作按钮
	private static JButton btnNewButton1;
	//停止按钮
	private static JButton btnNewButton2;
	//构建虚拟路灯窗口
	public Lamps(String lampId, Socket client) {
		//路灯id
		lightId = lampId;
		//用户与本地服务器建立联系的套接字
		clientSocket = client;
		//初始路灯为关闭状态
		state = false;
		
		//纯粹为了好看
		try {
			//设置当前外观为当前系统的风格
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e1) {
			e1.printStackTrace();
		} catch (InstantiationException e1) {
			e1.printStackTrace();
		} catch (IllegalAccessException e1) {
			e1.printStackTrace();
		} catch (UnsupportedLookAndFeelException e1) {
			e1.printStackTrace();
		}
		//改变程序的LookAndFeel外观时，通过调用这个方法来刷新该界面
		SwingUtilities.updateComponentTreeUI(this);
		
		//显示当前路灯id
		setTitle("当前路灯id为:"+lightId);
		//设置为用户不可以自由改变该窗体的大小
		setResizable(false);
		//设置用户在此窗体上发起 "close" 时默认执行的操作,DO_NOTHING_ON_CLOSE不执行任何操作
		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		//设置窗体出现的位置
		setBounds(600, 250, 688, 513);
		
		//创建虚拟路灯面板
		contentPane = new JPanel() {
			private static final long serialVersionUID = 1L;
			//设置窗口背景
			@Override
			protected void paintComponent(Graphics g) {
				super.paintComponent(g);
				g.drawImage(new ImageIcon("images\\\\背景.jpg").getImage(), 
						0, 0, getWidth(), getHeight(), null);
			}
		};
		//将容器装入窗口
		setContentPane(contentPane);
		//设置容器布局
		contentPane.setLayout(null);

		//温度信息显示区域
		//JScrollPane是带有滚动条的面板
		JScrollPane scrollPane_Tem = new JScrollPane();
		//将温度信息显示面板添加入容器
		getContentPane().add(scrollPane_Tem);
		//设置温度信息面板位置
		scrollPane_Tem.setBounds(40, 30, 180, 80);
		//新建一个富文本框，可编辑显示图片，超链接，HTML代码等等
		textpane_Tem = new JTextPane();
		//设置为不可编辑状态
		textpane_Tem.setEditable(false); 
		//设置文本框内容字体
		textpane_Tem.setFont(new Font("sdf", Font.PLAIN, 23));
		//内容居中
		StyledDocument doc_Tem = textpane_Tem.getStyledDocument();
		SimpleAttributeSet center = new SimpleAttributeSet();
		StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
		doc_Tem.setParagraphAttributes(0, doc_Tem.getLength(), center, false);
		//创建一个视口，并将该文本框设置为视图
		//不直接向JScrollPane函数提供视图的JScrollPane程序应使用此方法来指定要在滚动条中显示的可滚动子项
		scrollPane_Tem.setViewportView(textpane_Tem);

		//湿度信息显示区域
		//JScrollPane是带有滚动条的面板
		JScrollPane scrollPane_Hum = new JScrollPane();
		//将湿度信息显示面板添加入容器
		getContentPane().add(scrollPane_Hum);
		//设置湿度信息面板位置
		scrollPane_Hum.setBounds(250, 30, 180, 80);
		//新建一个富文本框，可编辑显示图片，超链接，HTML代码等等
		textpane_Hum = new JTextPane();
		//设置为不可编辑状态
		textpane_Hum.setEditable(false); 
		//设置文本框内容字体
		textpane_Hum.setFont(new Font("sdf", Font.PLAIN, 23));
		//内容居中
		StyledDocument doc_Hum = textpane_Hum.getStyledDocument();
		StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
		doc_Hum.setParagraphAttributes(0, doc_Hum.getLength(), center, false);
		//创建一个视口，并将该文本框设置为视图
		//不直接向JScrollPane函数提供视图的JScrollPane程序应使用此方法来指定要在滚动条中显示的可滚动子项
		scrollPane_Hum.setViewportView(textpane_Hum);
		
		//环境照度信息显示区域
		//JScrollPane是带有滚动条的面板
		JScrollPane scrollPane_Light = new JScrollPane();
		//将环境照度信息显示面板添加入容器
		getContentPane().add(scrollPane_Light);
		//设置环境照度信息面板位置
		scrollPane_Light.setBounds(460, 30, 180, 80);
		//新建一个富文本框，可编辑显示图片，超链接，HTML代码等等
		textpane_Light = new JTextPane();
		//设置为不可编辑状态
		textpane_Light.setEditable(false); 
		//设置文本框内容字体
		textpane_Light.setFont(new Font("sdf", Font.PLAIN, 23));
		//内容居中
		StyledDocument doc_Light = textpane_Light.getStyledDocument();
		StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
		doc_Light.setParagraphAttributes(0, doc_Light.getLength(), center, false);
		//创建一个视口，并将该文本框设置为视图
		//不直接向JScrollPane函数提供视图的JScrollPane程序应使用此方法来指定要在滚动条中显示的可滚动子项
		scrollPane_Light.setViewportView(textpane_Light);
		
		//路灯状态显示按钮，初始为关灯状态
		btnNewButton_state = new JButton("路灯" + lightId + "（关灯状态）");
		//字体设置
		btnNewButton_state.setFont(new Font("微软雅黑", Font.BOLD, 23));
		//位置及大小设置
		btnNewButton_state.setBounds(100, 180, 460, 130);
		//背景为黑色背景图片
		btnNewButton_state.setIcon(new ImageIcon("images\\黑色.png"));
		//文字为白色
		btnNewButton_state.setForeground(Color.WHITE);
		//显示文字
		btnNewButton_state.setHorizontalTextPosition(SwingConstants.CENTER);
		//将按钮加入面板
		getContentPane().add(btnNewButton_state);
		
		//设备地址信息显示区域
		//JScrollPane是带有滚动条的面板
		JScrollPane scrollPane_addr = new JScrollPane();
		//将环境照度信息显示面板添加入容器
		getContentPane().add(scrollPane_addr);
		//设置环境照度信息面板位置
		scrollPane_addr.setBounds(30, 368, 250, 70);
		//新建一个富文本框，可编辑显示图片，超链接，HTML代码等等
		textpane_Addr = new JTextPane();
		//设置为不可编辑状态
		textpane_Addr.setEditable(false); 
		//设置文本框内容字体
		textpane_Addr.setFont(new Font("sdf", Font.PLAIN, 23));
		//设置文本框中内容
		textpane_Addr.setText(clientSocket.getLocalSocketAddress().toString());
		//内容居中
		StyledDocument doc_Addr = textpane_Addr.getStyledDocument();
		StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
		doc_Addr.setParagraphAttributes(0, doc_Addr.getLength(), center, false);
		//创建一个视口，并将该文本框设置为视图
		//不直接向JScrollPane函数提供视图的JScrollPane程序应使用此方法来指定要在滚动条中显示的可滚动子项
		scrollPane_addr.setViewportView(textpane_Addr);
		
		try {
			//实例化一个对象输出流
			//客户端的Socket对象上的getOutputStream方法得到的输出流其实就是发送给服务器端的数据
			oos = new ObjectOutputStream(clientSocket.getOutputStream());
			
			//根据命令，创建一个客户端数据包
			ClientBean clientBean = creatClientBean(0, true);
			//将路灯当前信息写入输出流
			oos.writeObject(clientBean);
			//刷新缓冲
			oos.flush();
			
			CountDownLatch countDownLatch = new CountDownLatch(3);
			
			//启动客户接收线程
			new ClientInputThread().start();
			countDownLatch.countDown();
			
			//同时启动客户端上传数据线程
			new ClientOutputThread().start();
			countDownLatch.countDown();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//工作按钮
		btnNewButton1 = new JButton("工作");
		//设置为禁用
		btnNewButton1.setEnabled(false);
		//按钮字体样式
		btnNewButton1.setFont(new Font("微软雅黑", Font.BOLD, 25));
		//设置位置和大小
		btnNewButton1.setBounds(320, 368, 150, 70);
		//背景为黄色
		btnNewButton1.setIcon(new ImageIcon("images\\黄色.png"));
		//显示文字
		btnNewButton1.setHorizontalTextPosition(SwingConstants.CENTER);
		//加入最外层容器
		getContentPane().add(btnNewButton1);
		
		//给工作按钮注册事件
		btnNewButton1.addActionListener(new ActionListener() {
			//点击时触发调用
			public void actionPerformed(ActionEvent e) {
				//工作按钮不可用
				btnNewButton1.setEnabled(false);
				//停止按钮可用
				btnNewButton2.setEnabled(true);
				
				//允许客户端向服务器发送数据
				sendStop = false;
				//启动客户发送线程
				new ClientOutputThread().start();
			}
		});

		//停止按钮
		btnNewButton2 = new JButton("停止");
		//设置字体样式
		btnNewButton2.setFont(new Font("微软雅黑", Font.BOLD, 25));
		//设置位置和大小
		btnNewButton2.setBounds(493, 368, 150, 70);
		//设置背景
		btnNewButton2.setIcon(new ImageIcon("images\\红色.png"));
		//显示文字
		btnNewButton2.setHorizontalTextPosition(SwingConstants.CENTER);
		//加入最外层容器
		getContentPane().add(btnNewButton2);
		
		//侦听鼠标操作事件
		btnNewButton2.addActionListener(new ActionListener() {
			//按钮被点击时次奥运
			public void actionPerformed(ActionEvent e) {
				//终止客户端向服务器发送数据的线程
				sendStop = true;
				//工作按钮可用
				btnNewButton1.setEnabled(true);
				//停止按钮不可用
				btnNewButton2.setEnabled(false);
			}
		});
		
		//点击窗体的×号则断开连接
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				//创建一个客户端数据包
				ClientBean clientBean = new ClientBean();
				//type为-1，告诉服务器我要断开连接
				clientBean.setType(-1);
				clientBean.setLightId(lightId);
				clientBean.setTimer(Util.getTimer());
				//将数据包发送给服务器
				sendMessage(clientBean);
			}
		});
	}

	//用户向服务器发送数据的进程
	class ClientOutputThread extends Thread {
		@Override
		public void run() {
			while(true) {
				//允许发送就发送
				if(!sendStop) {
					//创建一个客户端数据包
					ClientBean clientBean = creatClientBean(1, true);
					
					//将数据包发送给服务器
					sendMessage(clientBean);
					
					//每隔1s发一次数据
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
				} else { //不予许发送就退出
					return;
				}
			}
		}
	}
	
	//用户接收服务器端发送的命令或消息的线程
	class ClientInputThread extends Thread {
		@Override
		public void run() {
			try {
				//不停的从服务器接收信息
				while (true) {
					//实例化一个对象输入流，不断从服务器接收信息
					ois = new ObjectInputStream(clientSocket.getInputStream());
					//将接收到的字节转化成对象形式
					ServerBean serverBean = (ServerBean) ois.readObject();
					//根据服务器端的Type命令判断执行哪一段程序
					switch (serverBean.getType()) {
						//断开连接
						case -1: {
							return;
						}
						//关灯
						case 0: {
							state = false;
							btnNewButton_state.setText("路灯" + serverBean.getLampId() + "（关灯状态）");
							//背景为黑色
							btnNewButton_state.setIcon(new ImageIcon("images\\黑色.png"));
							//文字为白色
							btnNewButton_state.setForeground(Color.WHITE);
							break;
						}
						//开灯
						case 1: {
							state = true;
							btnNewButton_state.setText("路灯" + serverBean.getLampId() + "（开灯状态）");
							//背景为白色
							btnNewButton_state.setIcon(new ImageIcon("images\\白色.png"));
							//文字为黑色
							btnNewButton_state.setForeground(Color.BLACK);
							break;
						}
						default: {
							break;
						}
					}
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				if (clientSocket != null) {
					try {
						clientSocket.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.exit(0);
			}
		}
	}

	private ClientBean creatClientBean(int type, boolean isAlter) {
		ClientBean clientBean = new ClientBean();
		//type为-1请求断开连接
		//type为0时请求连接
		//type为1时上传数据
		clientBean.setType(type);
		//记录路灯id
		clientBean.setLightId(lightId);
		//记录路灯  请求连接时间/断开连接时间/发送数据的时间
		clientBean.setTimer(Util.getTimer());
		
		//isAlter为true时，表示面板信息改变；为false表示面板信息已经改变
		//没办法，没有感知设备，所以数据全是自己捏的，不然不需要这个参数，直接上传面板信息就行
		if(isAlter) {
			int rd;
			//记录路灯感知的温度
			rd = random.nextInt(3) + 36;
			textpane_Tem.setText("当前温度为：" + rd);
			clientBean.setTem(rd);
			//记录路灯感知的湿度
			rd = random.nextInt(10) + 45;
			textpane_Hum.setText("当前湿度为：" + rd);
			clientBean.setHum(rd);
			//记录路灯感知的环境照度
			rd = random.nextInt(15) + 30;
			textpane_Light.setText("当前环境照度为：" + rd);
			clientBean.setLight(rd);
		} else {
			//获取温度信息
			clientBean.setTem(new Integer(textpane_Tem.getText()));
			//获取湿度信息
			clientBean.setHum(new Integer(textpane_Hum.getText()));
			//获取环境照度信息
			clientBean.setLight(new Integer(textpane_Light.getText()));
		}
		
		//记录路灯的状态
		clientBean.setState(state);
		
		return clientBean;
	}
	private void sendMessage(ClientBean clientBean) {
		try {
			//实例化一个对象输出流输出给服务器
			oos = new ObjectOutputStream(clientSocket.getOutputStream());
			//将数据写入
			oos.writeObject(clientBean);
			//关闭输出流
			oos.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {}
}
